package com.durian.base.rxhttp.parse

import android.util.Log
import androidx.annotation.NonNull
import com.durian.base.rxhttp.download.OutputStreamFactory
import com.durian.base.rxhttp.exception.RxHttpResponseException
import com.durian.base.rxhttp.utils.IOUtil
import com.durian.base.rxhttp.utils.OkHttpCompat
import okhttp3.Response
import okhttp3.ResponseBody
import java.io.IOException
import java.io.OutputStream

/**
 * 说明：SuspendStreamParser
 * <p/>
 * 作者：fanly
 * <p/>
 * 类型：Class
 * <p/>
 * 时间：2021/10/20 10:25 下午
 * <p/>
 * 版本：version 1.0
 */
class SuspendStreamParser<T>(
    private val osFactory: OutputStreamFactory<T>,
    var progress: (suspend (Int, Long, Long) -> Unit)? = null,
) : SuspendParser<T>() {
    @Throws(IOException::class)
    override suspend fun onSuspendParse(response: Response): T {
        val body = throwIfFatal(response)
        val expandOutputStream = osFactory.getOutputStream(response)
        val expand = expandOutputStream.expand
        val os = expandOutputStream.os
        progress?.let {
            response.writeTo(body, os, it)
        } ?: IOUtil.write(body.byteStream(), os)
        removeCall()
        return expand
    }

    /**
     * 根据Http执行结果过滤异常
     *
     * @param response Http响应体
     * @return ResponseBody
     * @throws IOException 请求失败异常、网络不可用异常
     */
    @Throws(IOException::class)
    private fun throwIfFatal(@NonNull response: Response): ResponseBody {
        val body = response.body ?: throw RxHttpResponseException(response = response)
        if (!response.isSuccessful) {
            throw RxHttpResponseException(response = response,message = body.string())
        }
        return body
    }
}

@Throws(IOException::class)
private suspend fun Response.writeTo(
    body: ResponseBody,
    outStream: OutputStream,
    progress: suspend (Int, Long, Long) -> Unit
) {
    val offsetSize = OkHttpCompat.getDownloadOffSize(this)?.offSize ?: 0
    var contentLength = OkHttpCompat.getContentLength(this)
    if (contentLength != -1L) contentLength += offsetSize
    if (contentLength == -1L) {
        Log.e("RxHttp","Unable to calculate callback progress without `Content-Length` response header")
    }

    var lastProgress = 0
    var lastSize = 0L
    var lastRefreshTime = 0L

    IOUtil.suspendWrite(body.byteStream(), outStream) {
        val currentSize = it + offsetSize
        lastSize = currentSize
        if (contentLength == -1L) {
            //响应头里取不到contentLength，仅回调已下载字节数
            val curTime = System.currentTimeMillis()
            if (curTime - lastRefreshTime > 500) {
                progress(0, currentSize, contentLength)
                lastRefreshTime = curTime
            }
        } else {
            //当前进度 = 当前已读取的字节 * 100 / 总字节
            val currentProgress = ((currentSize * 100 / contentLength)).toInt()
            if (currentProgress > lastProgress) {
                lastProgress = currentProgress
                progress(currentProgress, currentSize, contentLength)
            }
        }
    }

    if (contentLength == -1L) {
        //响应头里取不到contentLength时，保证下载完成事件能回调
        progress(100, lastSize, contentLength)
    }
}